
package IntelSpam::Plugins;

use 1.0;

use strict;
use warnings;
use File::Path qw(rmtree);
use Data::Dumper;
use MIME::Parser;
use Module::Load;
use IntelSpam::Config;
use IntelSpam::Score;
use Log::Log4perl qw(get_logger);

our $VERSION = '1.0';
our $DEBUG = 1;

our $ifilters = {
};
our $cfg = {};
#our $filter_instances = {
#	'DummyFilter' => new IntelSpam::Filters::DummyFilter,
#	'SubjectFilter' => new IntelSpam::Filters::SubjectFilter,
#	'Blacklist' => new IntelSpam::Filters::Blacklist
#}
our $filter_insts = {};

our $logger = get_logger("IntelSpam::Plugins");

sub new ($) {
	my $this = bless {}, shift;
	$this;
}

sub read_config($){
	my $this = shift;
	my $filters = $cfg->getcfg('filters');
	my $af;
	
	if(defined $filters){

		my @arr_filters = ref($filters) eq 'ARRAY' ? @$filters : ($filters);
		foreach my $afilter (@arr_filters){
			my $class = "IntelSpam::Filters::" . $afilter;	
			#if($afilter eq 'DummyFilter'){
			#	$af = new IntelSpam::Filters::DummyFilter;
			#}elsif($afilter eq 'SubjectFilter'){
			#	$af = new IntelSpam::Filters::SubjectFilter;
			#}
			#$af = $filter_instances->{$afilter};
			$af = getplugin_inst($class);
			if(defined $af){
				my $registers = $af->get_registers;
				foreach my $reg (@$registers){
					my $section = $ifilters->{$reg} || [];
					push @$section, $af;
					
					$ifilters->{$reg} = $section;
				}
			}
		}
	}else{	
		print "No filter available.";
	}
	#print Dumper $ifilters;
}

sub setcfg($$){
	my $this = shift;
	$cfg = shift;
}

sub filter_envfrom($$$)
{
	my ($this, $ctx, $envfrom) = @_;
	my $privfilters = $ifilters->{'envfrom'};
	my $pscore = $ctx->getpriv()->{'score'};
	
	my @froms = $envfrom =~ /[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/ig;

	foreach my $af (@$privfilters){
		unless (ref($af) eq 'ARRAY'){
			$af->filter_envfrom($ctx, \@froms);
		}
	}
}

sub filter_envrcpt($$$)
{
	my ($this, $ctx, $envrcpt) = @_;
	my $privfilters = $ifilters->{'envrcpt'};
	my $pscore = $ctx->getpriv()->{'score'};

	my @rcpts = $envrcpt =~ /[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/ig;

	foreach my $af (@$privfilters){
		unless (ref($af) eq 'ARRAY'){
			$af->filter_envrcpt($ctx, \@rcpts);
		}
	}
}

sub filter_connect($$$)
{
	my ($this, $ctx, $hostname) = @_;
	my $privfilters = $ifilters->{'connect'};

	foreach my $af (@$privfilters){
		unless (ref($af) eq 'ARRAY'){
			$af->filter_connect($ctx, $hostname);
		}
	}
}

sub filter_body($$$){
	my ($this, $ctx, $body) = @_;
	my $privfilters = $ifilters->{'body'};
	my $pscore = $ctx->getpriv()->{'score'};
	
	my $parser = new MIME::Parser;
	my $tmpdir = "/var/tmp/mime-tmp-" . rand(10000);
	$logger->debug("preparng temp directory $tmpdir");
	unless((-d $tmpdir) or mkdir $tmpdir,0755) { $logger->error("mkdir: $!"); die "mkdir: $!"; }
    	unless (-w $tmpdir) { $logger->error("can't write to directory"); die "can't write to directory";  }
    	$parser->output_dir($tmpdir);
	$logger->debug("prepend header...");
	my $mimeh;	
	$mimeh = "Content-Transfer-Encoding: " . $ctx->getpriv()->{'cte'} . "\n" if defined($ctx->getpriv()->{'cte'});
	$mimeh .= "Content-Type: ". $ctx->getpriv()->{'content-type'} . "\n";
	
	my $entity = $parser->parse_data($mimeh . $body);

	if($entity->head->mime_type =~ /text\/plain/i){
		my $bh = $entity->bodyhandle->open("w");
		print $bh $body;
		$bh->close;
	}
	#print Dumper $privfilters;
	foreach my $af (@$privfilters){
		unless (ref($af) eq 'ARRAY'){
			my $score = 0;
			$score = $af->filter_body($ctx, $entity);
		}
	}
	$logger->debug("removing temp directory.");
	rmtree $tmpdir;
}
sub filter_header($$$$){
	my $this = shift;
	my $ctx = shift;
	my $key = shift;
	my $value = shift;
	my $privfilters = $ifilters->{'header'};
	my $pscore = $ctx->getpriv()->{'score'};
	
	if( lc($key) eq 'content-type'){
		$ctx->getpriv()->{'content-type'} = $value;
	}elsif( lc($key) eq 'content-transfer-encoding'){
		$ctx->getpriv()->{'cte'} = $value;
	}
	#print Dumper $privfilters;
	foreach my $af (@$privfilters){
		unless (ref($af) eq 'ARRAY'){
			$af->filter_header($ctx, $key, $value);
		}
	}
}

sub getplugin_inst($){
	my $class = shift;
	my $inst = $filter_insts->{$class};
	if( defined($inst) ){
		return $inst;
	}else{
		load $class;	
		$inst = $class->new;
		$inst->set_cfg($cfg);
		$filter_insts->{$class} = $inst;
		return $inst;
	}
}
